package gui;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.commons.lang3.StringUtils;

import eu.schudt.javafx.controls.calendar.DatePicker;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Dialogs;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class DateEditorController {

	private Main mainApp;
	private Stage dialogStage;

	@FXML private HBox hboxDatePicker;
	@FXML private TextField txtHours; 
	@FXML private TextField txtMinutes;
	@FXML private TextField txtSeconds;
	@FXML private TextField txtMilliseconds;
	@FXML private TextField txtTimezone;

	private boolean okClicked = false;
	private String outputDate = "";
	private DatePicker datePicker;

	public boolean isOkClicked(){
		return okClicked;		
	}

	/**
	 * Initializes the controller class. This method is automatically called
	 * after the fxml file has been loaded.
	 */
	@FXML
	private void initialize() {
		datePicker = new DatePicker(Locale.getDefault());
		hboxDatePicker.getChildren().add(datePicker);		

		datePicker.getCalendarView().todayButtonTextProperty().set("Today");
		datePicker.getCalendarView().setShowWeeks(false);

		Tooltip tooltip = new Tooltip("Time zone is in minutes Range: [-840..840]");
		txtTimezone.setTooltip(tooltip);
		
		/*
		 * Set Key press event on ENTER
		 */
		datePicker.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
		
		txtHours.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
		
		txtMinutes.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
		
		txtSeconds.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
		
		txtMilliseconds.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
		
		txtTimezone.setOnKeyPressed(new EventHandler<KeyEvent>() {
	        public void handle(KeyEvent ke) {
	            if (ke.getCode() == KeyCode.ENTER) {
	               handleOk();
	            }
	        }
	    });
	}

	public void setInputDate(String date){
		XMLGregorianCalendar xmlDate = null;
		if(date != null && !date.equals("")){	
			try {
				xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(date);
			} catch (DatatypeConfigurationException e) {
				e.printStackTrace();
			}
		}
		else{
			GregorianCalendar c = new GregorianCalendar();
			c.setTime(new Date());
			try {
				xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
			} catch (DatatypeConfigurationException e) {
				e.printStackTrace();
			}
		}

		String str_date = "";
		str_date += (xmlDate.getDay()) + "-" + (xmlDate.getMonth()) + "-" + xmlDate.getYear();
		txtHours.setText(Integer.toString(xmlDate.getHour()));
		txtMinutes.setText(Integer.toString(xmlDate.getMinute()));
		txtSeconds.setText(Integer.toString(xmlDate.getSecond()));
		txtMilliseconds.setText(Integer.toString(xmlDate.getMillisecond()));
		txtTimezone.setText(Integer.toString(xmlDate.getTimezone()));

		DateFormat formatter ; 
		Date newDate = null; 
		formatter = new SimpleDateFormat("dd-MM-yyyy");
		try {
			newDate = (Date)formatter.parse(str_date);
		} catch (ParseException e) {
			e.printStackTrace();
		} 

		datePicker.setSelectedDate(newDate);		
	}

	/**
	 * Called when the user clicks ok. Stores all changes to the object
	 */
	@FXML
	private void handleOk() {

		String hours = txtHours.getText();
		String minutes = txtMinutes.getText();
		String seconds = txtSeconds.getText();
		String milliseconds = txtMilliseconds.getText();
		String timezone = txtTimezone.getText();

		if(!StringUtils.isNumeric(hours) || Integer.parseInt(hours) < 0 || Integer.parseInt(hours) > 23){
			Dialogs.showErrorDialog(dialogStage, "Invalid Hour value. Please enter a value in the range [0-23]");
			txtHours.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtHours.requestFocus();
				}
			});
			return;
		}

		if(!StringUtils.isNumeric(minutes) || Integer.parseInt(minutes) < 0 || Integer.parseInt(minutes) > 59){
			Dialogs.showErrorDialog(dialogStage, "Invalid Minute value. Please enter a value in the range [0-59]");
			txtMinutes.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtMinutes.requestFocus();
				}
			});
			return;
		}

		if(!StringUtils.isNumeric(seconds) || Integer.parseInt(seconds) < 0 || Integer.parseInt(seconds) > 59){
			Dialogs.showErrorDialog(dialogStage, "Invalid Seconds value. Please enter a value in the range [0-59]");
			txtSeconds.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtSeconds.requestFocus();
				}
			});
			return;
		}	

		if(!StringUtils.isNumeric(milliseconds) || Integer.parseInt(milliseconds) < 0 || Integer.parseInt(milliseconds) > 999){
			Dialogs.showErrorDialog(dialogStage, "Invalid Milliseconds value. Please enter a value in the range [0-999]");
			txtMilliseconds.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtMilliseconds.requestFocus();
				}
			});
			return;
		}

		try{
			Integer.parseInt(timezone);
		}catch(NumberFormatException e){
			Dialogs.showErrorDialog(dialogStage, "Invalid Timezone value. Please enter a value in the range [-840..840] minutes");
			txtTimezone.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtTimezone.requestFocus();
				}
			});
			return;
		}
		
		if(Integer.parseInt(timezone) < -840 || Integer.parseInt(timezone) > 840){
			Dialogs.showErrorDialog(dialogStage, "Invalid Timezone value. Please enter a value in the range [-840..840] minutes");
			txtTimezone.selectAll();
			Platform.runLater(new Runnable() {
				@Override
				public void run() {
					txtTimezone.requestFocus();
				}
			});
			return;
		}

		Date d = datePicker.getSelectedDate();
		Calendar cal = Calendar.getInstance();
		cal.setTime(d);
		try {
			 XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance()
					 .newXMLGregorianCalendar(
							 cal.get(Calendar.YEAR), 
							 cal.get(Calendar.MONTH)+1,
							 cal.get(Calendar.DAY_OF_MONTH),
							 Integer.parseInt(hours),
							 Integer.parseInt(minutes),
							 Integer.parseInt(seconds),
							 Integer.parseInt(milliseconds),
							 Integer.parseInt(timezone));
			 outputDate += xmlDate.toString();
		 } catch (NumberFormatException e) {
			 e.printStackTrace();
		 } catch (DatatypeConfigurationException e) {
			 e.printStackTrace();
		 }

		 okClicked = true;
		 dialogStage.close();
	}


	/**
	 * Called when the user clicks cancel.
	 */
	@FXML
	private void handleCancel() {
		dialogStage.close();
	}

	public String getOutputDate(){
		return outputDate;
	}

	/**
	 * Is called by the main application to give a reference back to itself.
	 * 
	 * @param mainApp
	 */
	public void setMainApp(Main mainApp) {
		this.mainApp = mainApp;
	}

	/**
	 * Sets the stage of this dialog.
	 * @param dialogStage
	 */
	public void setDialogStage(Stage dialogStage) {
		this.dialogStage = dialogStage;
	}
}
